package io.github.eric.urpc.core.serializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import io.github.eric.urpc.core.rpc.Message;

import java.io.IOException;

public class JsonMessageSerializer implements MessageSerializer {
    private static final ThreadLocal<ObjectMapper> OBJECT_MAPPER_THREAD_LOCAL = new InheritableThreadLocal<>();

    private ObjectMapper getCurObjectMapper() {
        ObjectMapper objectMapper = OBJECT_MAPPER_THREAD_LOCAL.get();
        if (objectMapper == null) {
            objectMapper = new ObjectMapper();
            objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
            objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
            OBJECT_MAPPER_THREAD_LOCAL.set(objectMapper);
        }
        return objectMapper;
    }

    @Override
    public <T extends Message> byte[] serialize(T msg) {
        try {
            return getCurObjectMapper().writeValueAsBytes(msg);
        } catch (JsonProcessingException e) {
            throw new IllegalStateException(String.format("serialize object failed. object:%s", msg), e);
        }
    }

    @Override
    public Object deserialize(byte[] bytes, Class<?> clazz) {
        try {
            return getCurObjectMapper().readValue(bytes, clazz);
        } catch (IOException e) {
            throw new IllegalStateException("deserialize object failed.", e);
        }
    }
}
